using System;
using System.Collections.Generic;
using System.Data;
using NHibernate;
using NHibernate.SqlTypes;
using NHibernate.UserTypes;

namespace Core.Domain.Enums
{
  ///<summary></summary>
  ///<typeparam name="T"></typeparam>
  public abstract class EnumGeneric<T> : IUserType
  {
    protected EnumGeneric()
    {
    }

    ///<summary>List of items</summary>
    private readonly string _dataValue;

    ///<summary>A list of the items in this enum</summary>
    public static IList<T> Items;

    ///<summary></summary>
    ///<param name="dataValue"></param>
    protected EnumGeneric(string dataValue)
    {
      Items = new List<T>();
      _dataValue = dataValue;
    }

    ///<summary>Convert this string to a Value</summary>
    ///<param name="value"></param>
    ///<returns></returns>
    public abstract T Parse(string value);

    public override string ToString()
    {
      return _dataValue;
    }

    ///<summary>The inner value. Also returned by ToString()</summary>
    public string InnerValue
    {
      get { return _dataValue; }
    }

    public new bool Equals(object x, object y)
    {
      if (x == null || y == null)
      {
        return false;
      }
      return ((EnumGeneric<T>) x)._dataValue.Equals(((EnumGeneric<T>) y)._dataValue);
    }

    public int GetHashCode(object x)
    {
      return ((EnumGeneric<T>) x)._dataValue.GetHashCode();
    }

    public object NullSafeGet(IDataReader rs, string[] names, object owner)
    {
      //We get the string from the database using the NullSafeGet used to get strings 
      var value = (string)NHibernateUtil.String.NullSafeGet(rs, names[0]);
      return Parse(value);
    }

    public void NullSafeSet(IDbCommand cmd, object value, int index)
    {
      //Set the value using the NullSafeSet implementation for string from NHibernateUtil
      if (value == null)
      {
        NHibernateUtil.String.NullSafeSet(cmd, null, index);
        return;
      }
      value = ((EnumGeneric<T>)value)._dataValue;
      NHibernateUtil.String.NullSafeSet(cmd, value, index);
    }

    public object DeepCopy(object value)
    {
      if (value == null)
      {
        return null;
      }
      return Parse(value.ToString());
    }

    public object Replace(object original, object target, object owner)
    {
      return original;
    }

    public object Assemble(object cached, object owner)
    {
      return cached;
    }

    public object Disassemble(object value)
    {
      return value;
    }

    public SqlType[] SqlTypes
    {
      get
      {
        var types = new SqlType[1];
        types[0] = new SqlType(DbType.String);
        return types;
      }
    }

    public Type ReturnedType
    {
      get
      {
        return typeof (T);
      }
    }

    public bool IsMutable
    {
      get
      { return false; }
    }
  }
}